﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Controls.Primitives;
using System.Globalization;
using System.Threading;
using PSE.Framework.UI.Controls.SmartClient.Validation;

using System.ComponentModel;
using System.Runtime.InteropServices;

namespace PSE.Framework.UI.Controls.SmartClient
{
    [DefaultProperty("InternalText")]
	public partial class DatePicker : Control, IValidatableObject
	{
		#region Properties
        private System.Windows.Controls.Grid PART_RootGrid;
		protected const string RangeValidationRuleName = "RangeValidator";
		protected const string RequiredValidationRuleName = "RequiredValidator";
		protected const string DateValidationRuleName = "DateValidator";
		private string DateMaskFormat;
		private int firstyear = (int)DateTime.MinValue.Year; //Usada para navegar através dos anos;
		private int lastyear = (int)DateTime.MaxValue.Year;  //Usada para navegar através dos anos;
		private List<DateTime> oldDates = new List<DateTime>();
		internal int yearstartposition;
		internal int monthstartposition;
		internal int daystartposition;
		private int index;
		private bool AllowUpdate = true;                     //Flag - Controla refresh do calendário;
		private bool JumpThruReload = false;                 //Flag - Controla refresh do calendário quando for marcar item selecionado;
		private bool _isEditing;
		private bool IsEditing
		{
			get { return _isEditing; }
			set { _isEditing = value; }
		}
		private bool _isOpen = false;
		private DateTime _selectionDate = DateTime.MinValue; //Memória de navegação dos dias;
		private DateTime Date                                //Retorna ou seta a última data selecionada;
		{
			get { return _date; }
			set
			{
				_date = value;
			}
		}
		private DateTime _minDate = DateTime.MinValue;
		private DateTime _maxDate = DateTime.MaxValue;
		private DateTime _date = DateTime.MinValue;          //Memória da propriedade Date;
		private const DayOfWeek FirstDayOfWeek = 0;          //Define primeiro dia da semana;
		private enmTypeSelection selecao;
		private List<enmTypeSelection> order = new List<enmTypeSelection>();
		private List<int> startorder = new List<int>();
        System.Windows.Controls.ListBox Semana = null;
        System.Windows.Controls.ListBox DP = null;
		TextBox txtData = null;
        System.Windows.Controls.Button btBackward = null;
        System.Windows.Controls.Button btForward = null;
        System.Windows.Controls.Button btDay = null;
        System.Windows.Controls.Button btMonth = null;
        System.Windows.Controls.Button btPopUp = null;
        System.Windows.Controls.Button btnAcima = null;
        System.Windows.Controls.Button btnAbaixo = null;
        System.Windows.Controls.Button btYear = null;
		System.Windows.Controls.Primitives.Popup Calendar = null;

		private List<bool> ValidationState = new List<bool>();

		#endregion

		#region Dependency Properties

		public static readonly DependencyProperty modeCalendarProperty = DependencyProperty.Register("modeCalendar", typeof(ModeCalendar), typeof(DatePicker), new UIPropertyMetadata(ModeCalendar.Week));
		public static readonly DependencyProperty MinDateProperty = DependencyProperty.Register("MinDate", typeof(DateTime), typeof(DatePicker), new UIPropertyMetadata(DateTime.MinValue, OnMinDatePropertyChange));
		public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(DateTime?), typeof(DatePicker), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnChangeValue));
		public static readonly DependencyProperty MaxDateProperty = DependencyProperty.Register("MaxDate", typeof(DateTime), typeof(DatePicker), new UIPropertyMetadata(DateTime.MaxValue, OnMaxDatePropertyChange));
		public static readonly DependencyProperty RequiredErrorMessageProperty = DependencyProperty.Register("RequiredErrorMessage", typeof(string), typeof(DatePicker), new FrameworkPropertyMetadata("Infra.Controls.Message.CampoObrigatorio", OnRequiredMessagePropertyChange));
		public static readonly DependencyProperty RangeOverflowErrorMessageProperty = DependencyProperty.Register("RangeOverflowErrorMessage", typeof(string), typeof(DatePicker), new FrameworkPropertyMetadata("Infra.Controls.Message.DataForaIntervalo", OnRangeMessagePropertyChange));
		public static readonly DependencyProperty IsRequiredProperty = DependencyProperty.Register("IsRequired", typeof(bool), typeof(DatePicker), new PropertyMetadata(false, OnIsRequiredPropertyChanged));
		protected static readonly DependencyProperty InternalTextProperty = DependencyProperty.Register("InternalText", typeof(string), typeof(DatePicker), new UIPropertyMetadata(""));
		public static readonly DependencyProperty InvalidDateErrorMessageProperty = DependencyProperty.Register("InvalidDateErrorMessage", typeof(string), typeof(DatePicker), new FrameworkPropertyMetadata("Infra.Controls.Message.DataInvalida", OnInvalidMessagePropertyChange));


		/// <summary>
		/// Define a data minima que pode ser digitada ou selecionada no DatePicker;
		/// </summary>
		public DateTime MinDate
		{
			get { return (DateTime)GetValue(MinDateProperty); }
			set { SetValue(MinDateProperty, value); }
		}
		/// <summary>
		/// Define se o controle será obrigatório ou não
		/// </summary>
		public bool IsRequired
		{
			get { return (bool)GetValue(IsRequiredProperty); }
			set { SetValue(IsRequiredProperty, value); }
		}
		/// <summary>
		/// Define a data máxima que pode ser digitada ou selecionada no DatePicker;
		/// </summary>
		public DateTime MaxDate
		{
			get { return (DateTime)GetValue(MaxDateProperty); }
			set { SetValue(MaxDateProperty, value); }
		}
		/// <summary>
		/// Define a chave da mensagem de erro de obrigatoriedade
		/// </summary>
		public string RequiredErrorMessage
		{
			get { return (string)GetValue(RequiredErrorMessageProperty); }
			set { SetValue(RequiredErrorMessageProperty, value); }
		}
		/// <summary>
		/// Define a chave da mensagem de erro de uma data que não esteja entre o range das datas
		/// </summary>
		public string RangeOverflowErrorMessage
		{
			get { return (string)GetValue(RangeOverflowErrorMessageProperty); }
			set { SetValue(RangeOverflowErrorMessageProperty, value); }
		}
		/// <summary>
		/// Propriedade criada para validação da data
		/// </summary>
		protected string InternalText
		{
			get { return (string)GetValue(InternalTextProperty); }
			set { SetValue(InternalTextProperty, value); }
		}
		/// <summary>
		/// Define a chave da mensagem que será mostrada quando a data estiver inválida
		/// </summary>
		public string InvalidDateErrorMessage
		{
			get { return (string)GetValue(InvalidDateErrorMessageProperty); }
			set { SetValue(InvalidDateErrorMessageProperty, value); }
		}
		/// <summary>
		/// Define o valor do DatePicker
		/// </summary>
		public DateTime? Value
		{
			get { return (DateTime?)GetValue(ValueProperty); }
			set
			{
				SetValue(ValueProperty, value);
                //if (value == null)
                //{
                //    this.UpdateTarget(DatePicker.ValueProperty);
                //    this.UpdateTarget(DatePicker.InternalTextProperty);
                //    this.txtData.UpdateTarget(TextBox.TextProperty);
                //}
			}
		}
		//Flag - Controla "modo" do calendário;
		public ModeCalendar modeCalendar
		{
			get { return (ModeCalendar)GetValue(modeCalendarProperty); }
		}


		#endregion

		#region Dependecy properties events

		private static void OnChangeValue(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker SNDP = (DatePicker)obj;
			if (SNDP.Value.HasValue)
				SNDP.oldDates.Add(SNDP.Value.Value);
		}
		private static void OnMinDatePropertyChange(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}
		private static void OnMaxDatePropertyChange(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}
		private static void OnRequiredMessagePropertyChange(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}
		private static void OnRangeMessagePropertyChange(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}
		private static void OnInvalidMessagePropertyChange(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}
		private static void OnIsRequiredPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
		{
			//if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(obj))
			//    return;

			DatePicker instance = obj as DatePicker;
			if (instance != null)
				instance.UpdateValitadions();
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Construtor da classe DatePicker
		/// </summary>
		public DatePicker()
		{
			ValidationManager.InitializeValidation(this);

            if (Date == DateTime.MinValue)
				Date = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);

			if (_selectionDate == DateTime.MinValue)
				_selectionDate = Date;

			//eventos utilizados pelo controle de alteracoes
			this.PropertyChanged += new PropertyChangedEventHandler(_PropertyChanged);
			this.Loaded += new RoutedEventHandler(_Loaded);
			this.LostFocus += new RoutedEventHandler(DatePicker_LostFocus);

			System.Windows.DataObject.AddPastingHandler(this, new System.Windows.DataObjectPastingEventHandler(OnPasting));

		}

		/// <summary>
		/// Construtor da classe DatePicker
		/// </summary>
		/// <param name="StartingDate">Data na qual o calendário deve iniciar</param>
		public DatePicker(DateTime startingDate)
		{
			ValidationManager.InitializeValidation(this);

            Date = startingDate;

			if (_selectionDate == DateTime.MinValue)
				_selectionDate = Date.AddMonths(1);
			else
				_selectionDate = _selectionDate.AddMonths(1);

			//eventos utilizados pelo controle de alteracoes
			this.PropertyChanged += new PropertyChangedEventHandler(_PropertyChanged);
			this.Loaded += new RoutedEventHandler(_Loaded);
			this.LostFocus += new RoutedEventHandler(DatePicker_LostFocus);

		}
		#endregion

		/// <summary>
		/// Função que tratará os eventos após ter aplicado o template
		/// </summary>
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
            PART_RootGrid = this.GetTemplateChild("PART_RootGrid") as System.Windows.Controls.Grid;
            Semana = this.GetTemplateChild("Part_Semana") as System.Windows.Controls.ListBox;
            DP = this.GetTemplateChild("Part_DP") as System.Windows.Controls.ListBox;
			txtData = this.GetTemplateChild("Part_txtData") as TextBox;
            btBackward = this.GetTemplateChild("Part_btBackward") as System.Windows.Controls.Button;
            btForward = this.GetTemplateChild("Part_btForward") as System.Windows.Controls.Button;
            btDay = this.GetTemplateChild("Part_btDay") as System.Windows.Controls.Button;
            btMonth = this.GetTemplateChild("Part_btMonth") as System.Windows.Controls.Button;
            btYear = this.GetTemplateChild("Part_btYear") as System.Windows.Controls.Button;
            Calendar = this.GetTemplateChild("Part_Calendar") as System.Windows.Controls.Primitives.Popup;
            btPopUp = this.GetTemplateChild("Part_btPopUp") as System.Windows.Controls.Button;
            btnAcima = this.GetTemplateChild("Part_btnAcima") as System.Windows.Controls.Button;
            btnAbaixo = this.GetTemplateChild("Part_btnAbaixo") as System.Windows.Controls.Button;
			btPopUp.Click += new RoutedEventHandler(btPopUp_Click);
			btPopUp.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(btPopUp_PreviewMouseLeftButtonDown);
			btBackward.Click += new RoutedEventHandler(BackwardButton_Click);
			btDay.Click += new RoutedEventHandler(btDay_Click);
			btMonth.Click += new RoutedEventHandler(btMonth_Click);
			btYear.Click += new RoutedEventHandler(btYear_Click);
			btForward.Click += new RoutedEventHandler(ForwardButton_Click);
			txtData.GotFocus += new RoutedEventHandler(txtData_GotFocus);
			txtData.PreviewKeyDown += new KeyEventHandler(txtData_PreviewKeyDown);
			txtData.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(txtData_PreviewMouseLeftButtonDown);
			txtData.GotMouseCapture += new MouseEventHandler(txtData_GotMouseCapture);
			//DP.SelectionChanged += new SelectionChangedEventHandler(DP_SelectionChanged);
			DP.MouseDown += new MouseButtonEventHandler(DP_MouseDown);
			btnAbaixo.Click += new RoutedEventHandler(btnAbaixo_Click);
			btnAcima.Click += new RoutedEventHandler(btnAcima_Click);
			this.PreviewKeyDown += new KeyEventHandler(DatePicker_PreviewKeyDown);
			DP.MouseLeftButtonUp += new MouseButtonEventHandler(DP_MouseLeftButtonUp);
			DP.AddHandler(MouseDownEvent, new MouseButtonEventHandler(DP_MouseDown), true);
			Calendar.Closed += new EventHandler(Calendar_Closed);
			SetButtonOrder();
			SetButtonContent(Date);
			LoadWeek();
			DateConfiguration();
			selecao = enmTypeSelection.Day;
			selectDatePart(daystartposition, true);
			txtData.AllowDrop = false;
			Binding TextBinding = new Binding("InternalText");
			TextBinding.Mode = BindingMode.TwoWay;
			TextBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
			TextBinding.RelativeSource = RelativeSource.TemplatedParent;
			this.txtData.SetBinding(TextBox.TextProperty, TextBinding);
            //txtData.Text = DateMaskFormat;
            //this.InternalText = DateMaskFormat;
			ValidationConstrutor();
			this.PreviewGotKeyboardFocus += new KeyboardFocusChangedEventHandler(DatePicker_PreviewGotKeyboardFocus);
			this.PreviewLostKeyboardFocus += new KeyboardFocusChangedEventHandler(DatePicker_PreviewLostKeyboardFocus);
			LostFocusAllElements(this);
		}

		void DatePicker_LostFocus(object sender, RoutedEventArgs e)
		{
			if (IsAnyElementFocused(this))
				e.Handled = true;
			else
			{
				RaiseControlLostFocusEvent();
			}
		}

		private static object GetObjectDataFromPoint(System.Windows.Controls.ListBox source, Point point)
		{
			UIElement element = source.InputHitTest(point) as UIElement;

			if (element != null)
			{
                if (element is System.Windows.Controls.ListBoxItem)
					return element;

				while (element != source)
				{
					element = VisualTreeHelper.GetParent(element) as UIElement;

                    if (element is System.Windows.Controls.ListBoxItem)
						return element;
				}
			}

			return null;
		}

		void DP_MouseDown(object sender, MouseButtonEventArgs e)
		{
			System.Windows.Controls.ListBox listBox = (System.Windows.Controls.ListBox)sender;
			object listBoxItem = GetObjectDataFromPoint(listBox, e.GetPosition(listBox));

            if (!(listBoxItem is System.Windows.Controls.ListBoxItem))
				return;


			if (listBox.SelectedItems.Count > 0 && listBox.Items.Count > 0 && !JumpThruReload)
			{
                System.Windows.Controls.ListBox lb = (System.Windows.Controls.ListBox)sender;
				switch (modeCalendar)
				{
					case ModeCalendar.Week:
						if (lb.SelectedItems.Count > 0)
						{
							Thread.Sleep(100);
							CalendarDate cd = ((CalendarDate)lb.SelectedItems[0]);
							DateTime selectedDate = cd.Date;
							SetTextDate(selectedDate);
							Date = selectedDate;
							SetButtonContent(selectedDate);
							LoadDays();
							Calendar.IsOpen = false;
						}
						LockBackForward(true);
						MarkSelectedDay();
						e.Handled = true;
						break;
					case ModeCalendar.Month:
						if (listBox.Items.Count > 0)
						{
							Thread.Sleep(100);
							Date = DateChecking(Date.Year, lb.SelectedIndex + 1, Date.Day);
							SetTextDate(Date.Month.ToString(), enmTypeSelection.Month);
							DP.ItemsSource = null;
							ReLoadWeek();
							RotateMonth(Date);
							SetButtonContent(Date);
							LockBackForward(true);
							MarkSelectedDay();
						}
						e.Handled = true;
						break;
					case ModeCalendar.Year:
						if (listBox.Items.Count > 0)
						{
							Thread.Sleep(100);
							Date = DateChecking(Int32.Parse(listBox.SelectedItem.ToString()), Date.Month, Date.Day);
							SetTextDate(Date.Year.ToString(), enmTypeSelection.Year);
							LoadMonth();
							SetButtonContent(Date);
							LockBackForward(false);
						}
						e.Handled = true;
						break;
				}
			}
			this.txtData.Validate();
			txtData.Focus();


		}

		#region Focus
		private void ChildLostFocus(object sender, RoutedEventArgs e)
		{
			if (IsAnyElementFocused(this))
				e.Handled = true;
			//else
			//{
			//    RaiseControlLostFocusEvent();
			//}

			if (e.OriginalSource == txtData)
			{
				IsEditing = false;
			}
		}

		protected override void OnLostFocus(RoutedEventArgs e)
		{
			UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

			if (IsAnyElementFocused(this))
				e.Handled = true;
			else
			{
				base.OnLostFocus(e);
			}
		}

		private void LostFocusAllElements(object control)
		{
			if (!(control is UIElement))
				return;

			((UIElement)control).LostFocus += new RoutedEventHandler(ChildLostFocus);

			for (int i = 0; i < VisualTreeHelper.GetChildrenCount(control as DependencyObject); i++)
			{
				UIElement child = VisualTreeHelper.GetChild(control as DependencyObject, i) as UIElement;

				if (child != null)
				{
					child.LostFocus += new RoutedEventHandler(ChildLostFocus);
					LostFocusAllElements(child);
				}
			}

		}

		private void RaiseControlLostFocusEvent()
		{
			RoutedEventArgs e = new RoutedEventArgs(InternalLostFocusEvent, this);
			this.RaiseEvent(e);
		}

		void DatePicker_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
		{
			MaskController(true);
		}

		void DatePicker_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
		{
			MaskController(false);
		}

		private bool IsAnyElementFocused(object control)
		{
			bool hasFocus = false;

			if (!(control is UIElement)) return hasFocus;

			if (Calendar.IsOpen || ((UIElement)control).IsFocused || ((UIElement)control).IsKeyboardFocused || ((UIElement)control).IsKeyboardFocusWithin)
			{
				hasFocus = true;
			}
			else
			{
				for (int i = 0; i < VisualTreeHelper.GetChildrenCount(control as DependencyObject); i++)
				{
					UIElement child = VisualTreeHelper.GetChild(control as DependencyObject, i) as UIElement;

					if (child != null)
					{
						if (child.IsFocused || child.IsKeyboardFocused || child.IsKeyboardFocusWithin)
						{
							hasFocus = true;
							break;
						}
						else
						{
							hasFocus = IsAnyElementFocused(child);

							if (hasFocus)
							{
								break;
							}
						}
					}
				}
			}

			return hasFocus;
		}
		#endregion

		void Calendar_Closed(object sender, EventArgs e)
		{
			this.Validate();
		}

		#region Eventos

		public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DatePicker));
		/// <summary>
		/// Evento disparado depois do inicio da aplicação de um estilo 
		/// </summary>
		public event RoutedEventHandler ValueChanged
		{
			add { AddHandler(ValueChangedEvent, value); }
			remove { RemoveHandler(ValueChangedEvent, value); }
		}

		internal static readonly RoutedEvent InternalLostFocusEvent = EventManager.RegisterRoutedEvent("InternalLostFocus", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DatePicker));
		/// <summary>
		/// Evento disparado depois do inicio da aplicação de um estilo 
		/// </summary>
		internal event RoutedEventHandler InternalLostFocus
		{
			add { AddHandler(InternalLostFocusEvent, value); }
			remove { RemoveHandler(InternalLostFocusEvent, value); }
		}

		private void MaskController(bool showMask)
		{
			if (showMask)
			{
				if (txtData != null && String.IsNullOrEmpty(txtData.Text))
					txtData.Text = DateMaskFormat;
			}
			else
			{
				if (txtData != null && txtData.Text == DateMaskFormat)
					txtData.Text = "";
			}
		}
		protected override void OnGotFocus(RoutedEventArgs e)
		{
			base.OnGotFocus(e);

			if (txtData != null)
			{
				txtData.Focus();

			}
		}

		void DP_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
            if (((System.Windows.Controls.ListBox)sender).SelectedItems.Count > 0 && (((System.Windows.Controls.ListBox)sender).SelectedItems[0].ToString() == txtData.Text))
				Calendar.IsOpen = false;
		}

		void btnAcima_Click(object sender, RoutedEventArgs e)
		{
			adjustDate(enmTypeAdjust.Increase);
			txtData.Focus();

			//btnAcima.Focusable = true;
			//btnAcima.Focus();
			//btnAcima.Focusable = false;
		}
		void btnAbaixo_Click(object sender, RoutedEventArgs e)
		{
			adjustDate(enmTypeAdjust.Decrease);
			txtData.Focus();

			//btnAbaixo.Focusable = true;
			//btnAbaixo.Focus();
			//btnAbaixo.Focusable = false;
		}
		void DatePicker_PreviewKeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Z && Keyboard.Modifiers == ModifierKeys.Control)
			{
				if (oldDates.Count > 0)
				{
					if (Value == oldDates[oldDates.Count - 1])
					{
						oldDates.Remove(oldDates[oldDates.Count - 1]);
					}
					if (oldDates.Count > 0)
					{
						SetTextDate(oldDates[oldDates.Count - 1]);
						SetButtonContent(oldDates[oldDates.Count - 1]);
						oldDates.Remove(oldDates[oldDates.Count - 1]);
					}
				}
			}
		}
		private void txtData_PreviewKeyDown(object sender, KeyEventArgs e)
		{
			if ((e.Key == Key.D0 || e.Key == Key.NumPad0) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('0');
				e.Handled = true;
			}
			else if ((e.Key == Key.D1 || e.Key == Key.NumPad1) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('1');
				e.Handled = true;
			}
			else if ((e.Key == Key.D2 || e.Key == Key.NumPad2) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('2');
				e.Handled = true;
			}
			else if ((e.Key == Key.D3 || e.Key == Key.NumPad3) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('3');
				e.Handled = true;
			}
			else if ((e.Key == Key.D4 || e.Key == Key.NumPad4) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('4');
				e.Handled = true;
			}
			else if ((e.Key == Key.D5 || e.Key == Key.NumPad5) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('5');
				e.Handled = true;
			}
			else if ((e.Key == Key.D6 || e.Key == Key.NumPad6) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('6');
				e.Handled = true;
			}
			else if ((e.Key == Key.D7 || e.Key == Key.NumPad7) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('7');
				e.Handled = true;
			}
			else if ((e.Key == Key.D8 || e.Key == Key.NumPad8) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('8');
				e.Handled = true;
			}
			else if ((e.Key == Key.D9 || e.Key == Key.NumPad9) && Keyboard.Modifiers == ModifierKeys.None)
			{
				validateInput('9');
				e.Handled = true;
			}
			else if (e.Key == Key.Back)
			{
				removeDigit();
				e.Handled = true;
			}
			else if (e.Key == Key.Home)
			{
				selecao = order[0];
				index = startorder[0];
				e.Handled = true;
			}
			else if (e.Key == Key.End)
			{
				selecao = order[2];
				index = startorder[2];
				e.Handled = true;
			}
			else if (e.Key == Key.Delete)
			{
				deleteBlock();
				e.Handled = true;
			}
			else if (e.Key == Key.Tab)
			{
				switch (selecao)
				{
					case enmTypeSelection.Day:

						if (order[0] == enmTypeSelection.Day)
						{
							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
						}
						else if (order[1] == enmTypeSelection.Day)
						{
							e.Handled = true;

							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								selectDatePart(startorder[2], true);
								selecao = order[2];
							}
						}
						else if (order[2] == enmTypeSelection.Day)
						{

							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
							else
							{
								//this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
								selectDatePart(startorder[0], true);
								selecao = order[2];
							}
						}

						break;
					case enmTypeSelection.Month:

						if (order[0] == enmTypeSelection.Month)
						{
							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
						}
						else if (order[1] == enmTypeSelection.Month)
						{
							e.Handled = true;

							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								selectDatePart(startorder[2], true);
								selecao = order[2];
							}
						}
						else if (order[2] == enmTypeSelection.Month)
						{

							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
							else
							{
								//this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
								selectDatePart(startorder[0], true);
								selecao = order[2];
							}
						}

						break;
					case enmTypeSelection.Year:

						if (order[0] == enmTypeSelection.Year)
						{
							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
						}
						else if (order[1] == enmTypeSelection.Year)
						{
							e.Handled = true;

							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								selectDatePart(startorder[0], true);
								selecao = order[0];
							}
							else
							{
								selectDatePart(startorder[2], true);
								selecao = order[2];
							}
						}
						else if (order[2] == enmTypeSelection.Year)
						{
							if (Keyboard.Modifiers == ModifierKeys.Shift)
							{
								e.Handled = true;
								selectDatePart(startorder[1], true);
								selecao = order[1];
							}
							else
							{
								//this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
								selectDatePart(startorder[0], true);
								selecao = order[2];
								//break;
							}
						}

						break;
				}
				return;
			}
			else if (e.Key == Key.Up)
			{
				IncreaseValue();
				e.Handled = true;
				return;
			}
			else if (e.Key == Key.Down)
			{
				DecreaseValue();
				e.Handled = true;
				return;
			}
			else if (e.Key == Key.Right)
			{
				switch (selecao)
				{
					case enmTypeSelection.Day:
						if (order[0] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						else if (order[1] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[2] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						e.Handled = true;
						break;
					case enmTypeSelection.Month:
						if (order[0] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						else if (order[1] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[2] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						e.Handled = true;
						break;
					case enmTypeSelection.Year:
						if (order[0] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						else if (order[1] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[2] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						e.Handled = true;
						break;
				}
				return;
			}
			else if (e.Key == Key.Left)
			{
				switch (selecao)
				{
					case enmTypeSelection.Day:
						if (order[0] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[1] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						else if (order[2] == enmTypeSelection.Day)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						e.Handled = true;
						break;
					case enmTypeSelection.Month:
						if (order[0] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[1] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						else if (order[2] == enmTypeSelection.Month)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						e.Handled = true;
						break;
					case enmTypeSelection.Year:
						if (order[0] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[2], true);
							selecao = order[2];
						}
						else if (order[1] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[0], true);
							selecao = order[0];
						}
						else if (order[2] == enmTypeSelection.Year)
						{
							selectDatePart(startorder[1], true);
							selecao = order[1];
						}
						e.Handled = true;
						break;
				}
				return;
			}
			else if (e.Key == Key.Enter)
			{
				this.Validate();
			}
			else if (e.Key != Key.Enter && e.Key != Key.Escape)
			{
				e.Handled = true;
			}
		}
		private void txtData_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			IsEditing = true;
		}

		private void txtData_GotMouseCapture(object sender, MouseEventArgs e)
		{
			selectDatePart(((System.Windows.Controls.TextBox)(sender)).CaretIndex, true);
		}
		private void txtData_GotFocus(object sender, RoutedEventArgs e)
		{
			IsEditing = true;
			switch (selecao)
			{
				case enmTypeSelection.Day:
					selectDatePart(daystartposition, true);
					break;
				case enmTypeSelection.Month:
					selectDatePart(monthstartposition, true);
					break;
				case enmTypeSelection.Year:
					selectDatePart(yearstartposition, true);
					break;
				default:
					selectDatePart(startorder[0], true);
					break;
			}
		}
		private void txtData_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
			txtData.Focus();
			selectDatePart(((TextBox)sender).CaretIndex, true);
			e.Handled = true;
		}
		private void btPopUp_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			_isOpen = Calendar.IsOpen;
		}

		protected void OnPasting(object sender, DataObjectPastingEventArgs e)
		{
			Object ObjetoPasted = e.DataObject.GetData(System.Windows.DataFormats.StringFormat);
			bool ConteudoValido = false;
			string NovoTexto = "";

			//O Paste só será efetuado se for uma string
			if (ObjetoPasted is String && ObjetoPasted != null)
			{
				NovoTexto = (string)ObjetoPasted;

				if (!String.IsNullOrEmpty(NovoTexto))
					ConteudoValido = ValidateValue(NovoTexto);
			}

			//Cancela o pasting de conteúdo
			e.CancelCommand();
			e.Handled = true;

			//Acrescenta o past pelo value
			if (ConteudoValido)
				this.Value = DateTime.Parse(NovoTexto);
		}

		#region ValidateValue
		private bool ValidateValue(string text)
		{
			DateTime dateValue;

			if (DateTime.TryParse(text, out dateValue))
				return true;
			else
				return false;
		}
		#endregion

		private void DP_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{

		}

		private DateTime DateChecking(int year, int month, int day)
		{
			string date = day.ToString().PadLeft(2, '0') + "/" + month.ToString().PadLeft(2, '0') + "/" + year.ToString();
			DateTime dateOut;

			if (!(DateTime.TryParse(date, null, DateTimeStyles.None, out dateOut)))
				dateOut = new DateTime(year, month, new System.Globalization.GregorianCalendar().GetDaysInMonth(year, month));

			return dateOut;

		}
		private void ForwardButton_Click(object sender, RoutedEventArgs e)
		{
			switch (modeCalendar)
			{
				case ModeCalendar.Year:
					YearsForward();
					break;
				case ModeCalendar.Week:
					NextMonth();
					break;
			}
		}
		private void BackwardButton_Click(object sender, RoutedEventArgs e)
		{
			switch (modeCalendar)
			{
				case ModeCalendar.Year:
					YearsBackward();
					break;
				case ModeCalendar.Week:
					LastMonth();
					break;
			}
		}
		private void btPopUp_Click(object sender, RoutedEventArgs e)
		{
			if (_isOpen)
			{
				txtData.Focus();

				if (modeCalendar != ModeCalendar.Week)
				{
					LockBackForward(true);
					LoadWeek();
				}
				MarkSelectedDay();
				Calendar.IsOpen = false;
				_isOpen = false;
			}
			else
			{
				if (Value.HasValue)
				{
					Date = Value.Value;
					LockBackForward(true);
					LoadWeek();
					SetButtonContent(Date);
				}
				Calendar.IsOpen = true;
				_isOpen = true;
			}
		}
		private void btDay_Click(object sender, RoutedEventArgs e)
		{
			if (modeCalendar != ModeCalendar.Week)
			{
				LockBackForward(true);
				ReLoadWeek();
				RotateMonth(_selectionDate);
				this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Week);
			}
		}
		private void btMonth_Click(object sender, RoutedEventArgs e)
		{
			if (modeCalendar != ModeCalendar.Month)
			{
				LockBackForward(false);
				LoadMonth();
				this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Month);
			}
		}
		private void btYear_Click(object sender, RoutedEventArgs e)
		{
			if (modeCalendar != ModeCalendar.Year)
			{
				LockBackForward(true);
				LoadYear(Date.Year);
				this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Year);
			}
		}

		#endregion

		#region Enums

		/// <summary>
		/// Enumerador - Possui os modos de apresentação do calendário Semana, Mes e Ano
		/// </summary>
		public enum ModeCalendar
		{
			Week,
			Month,
			Year
		}
		/// <summary>
		/// Enumerador - Possui os modos de seleção do calendário Dia, Mes e Ano
		/// </summary>
		private enum enmTypeSelection
		{
			Day,
			Month,
			Year
		}
		/// <summary>
		/// Enumerador - Possui os modos de alteração do valor do calendário Incrementar ou Decrementar
		/// </summary>
		private enum enmTypeAdjust
		{
			Increase,
			Decrease
		}

		#endregion

		#region Funções Privadas

		private void ValidationConstrutor()
		{
			//ValidationManager.InitializeValidation(this);

			Binding ValueBinding = new Binding("Value");
			ValueBinding.Mode = BindingMode.TwoWay;
			ValueBinding.Converter = new DateConverter(this);
			ValueBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
			ValueBinding.RelativeSource = RelativeSource.Self;
			this.SetBinding(DatePicker.InternalTextProperty, ValueBinding);

			if (!this.ValidationRules.Contains(RequiredValidationRuleName))
			{
				RequiredDateValidationRule reqValidation = new RequiredDateValidationRule(this, DatePicker.InternalTextProperty);
				reqValidation.Name = RequiredValidationRuleName;

				this.ValidationRules.Add(reqValidation);
				reqValidation.ErrorContent = RequiredErrorMessage;
				reqValidation.IsEnabled = this.IsRequired;
			}

			if (!this.ValidationRules.Contains(DateValidationRuleName))
			{
				DateValidationRule validation = new DateValidationRule(this, DatePicker.InternalTextProperty);
				this.ValidationRules.Add(validation);
				validation.Name = DateValidationRuleName;
				validation.ErrorContent = InvalidDateErrorMessage;
			}
			if (!this.ValidationRules.Contains(RangeValidationRuleName))
			{
				RangeDateValidationRule rangeValidation = new RangeDateValidationRule(this, DatePicker.InternalTextProperty);
				rangeValidation.Name = RangeValidationRuleName;
				this.ValidationRules.Add(rangeValidation);
				rangeValidation.Maximum = (IComparable)MaxDate;
				rangeValidation.Minimum = (IComparable)MinDate;
				rangeValidation.ErrorContent = RangeOverflowErrorMessage;
				rangeValidation.IsEnabled = true;
			}

			EventValidationTrigger trigger = new EventValidationTrigger(ValidationTriggerScope.Self, InternalLostFocusEvent);
			trigger.ContinueRoutingOnError = true;
			if (!this.ValidationTriggers.Contains(trigger))
			{
				this.ValidationTriggers.Add(trigger);
			}
		}
		private void LoadDays()
		{
			if ((DP.SelectedItems.Count > 0 && ((CalendarDate)DP.SelectedItem).IsOtherMonth) || AllowUpdate)
			{
				FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
				f.SetValue(UniformGrid.RowsProperty, 6);
				f.SetValue(UniformGrid.ColumnsProperty, 7);
				DP.ItemsPanel = new ItemsPanelTemplate(f);

				DateTime DateWithDayOne = new DateTime(Date.Year, Date.Month, 1);
				DP.ItemsSource = GetDays(DateWithDayOne, DateWithDayOne.AddMonths(1).AddMilliseconds(-1), FirstDayOfWeek);
				DP.DisplayMemberPath = "Date.Day";
				if (this.Value.HasValue)
					if (this.Value.Value.Year == Date.Year && this.Value.Value.Month == Date.Month)
						MarkSelectedDay();
					else
						DP.SelectedIndex = -1;
			}
			AllowUpdate = false;
		}
		private void LoadWeek()
		{
			FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
			f.SetValue(UniformGrid.RowsProperty, 1);
			f.SetValue(UniformGrid.ColumnsProperty, 7);
			Semana.ItemsPanel = new ItemsPanelTemplate(f);
			Semana.ItemsSource = DaysOfWeek();
			this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Week);
			AllowUpdate = true;
			LoadDays();
		}
		private void ReLoadWeek()
		{
			FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
			f.SetValue(UniformGrid.RowsProperty, 1);
			f.SetValue(UniformGrid.ColumnsProperty, 7);
			Semana.ItemsPanel = new ItemsPanelTemplate(f);
			Semana.ItemsSource = DaysOfWeek();
			this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Week);
		}
		private void LoadMonth()
		{
			Semana.ItemsSource = null;
			FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
			f.SetValue(UniformGrid.RowsProperty, 3);
			f.SetValue(UniformGrid.ColumnsProperty, 4);
			DP.ItemsPanel = new ItemsPanelTemplate(f);
			DP.ItemsSource = null;
			DP.ItemsSource = Months();
			DP.DisplayMemberPath = "";
			DP.SelectedIndex = -1;
			this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Month);
		}
		private void LoadYear(int year)
		{
			Semana.ItemsSource = null;
			FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
			f.SetValue(UniformGrid.RowsProperty, 5);
			f.SetValue(UniformGrid.ColumnsProperty, 5);
			f.SetValue(UniformGrid.MarginProperty, LoadUniformGridMargin(0, 10, 15, 15));
			DP.ItemsPanel = new ItemsPanelTemplate(f);
			DP.ItemsSource = Years(year);
			DP.DisplayMemberPath = "";
			DP.SelectedIndex = -1;
			this.SetValue(DatePicker.modeCalendarProperty, ModeCalendar.Year);
		}
		private void YearsForward()
		{
			firstyear = firstyear + 25;
			int year = firstyear + 12;
			if (year > DateTime.MaxValue.Year)
				LoadYear((int)DateTime.MaxValue.Year);
			else
				LoadYear(year);
		}
		private void YearsBackward()
		{
			firstyear = firstyear - 25;
			int year = firstyear + 12;
			if (year < DateTime.MinValue.Year)
				LoadYear((int)DateTime.MinValue.Year);
			else
				LoadYear(year);
		}
		private void NextMonth()
		{
			if (Value.HasValue)
				_selectionDate = Value.Value.AddMonths(1);
			else
				_selectionDate = DateTime.Now.AddMonths(1);
			RotateMonth(_selectionDate);
			SetButtonContent(_selectionDate);
			Value = _selectionDate;
			MarkSelectedDay();
		}
		private void LastMonth()
		{
			if (Value.HasValue)
				_selectionDate = Value.Value.AddMonths(-1);
			else
				_selectionDate = DateTime.Now.AddMonths(-1);
			RotateMonth(_selectionDate);
			SetButtonContent(_selectionDate);
			Value = _selectionDate;
			MarkSelectedDay();
		}
		private void LockBackForward(bool isEnabled)
		{
			if (isEnabled)
			{
				btBackward.Visibility = Visibility.Visible;
				btForward.Visibility = Visibility.Visible;
			}
			else
			{
				btBackward.Visibility = Visibility.Hidden;
				btForward.Visibility = Visibility.Hidden;
			}
		}
		private void SetButtonContent(DateTime data)
		{
			btDay.Content = data.Day.ToString();
			btMonth.Content = MonthName(data.Month);
			btYear.Content = data.Year.ToString();
		}
		private void SetButtonOrder()
		{
			string shortdatepattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern.Replace(CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator, "");

			while (shortdatepattern.IndexOf("dd") != -1)
				shortdatepattern = shortdatepattern.Replace("dd", "d");
			while (shortdatepattern.IndexOf("MM") != -1)
				shortdatepattern = shortdatepattern.Replace("MM", "M");
			while (shortdatepattern.IndexOf("yy") != -1)
				shortdatepattern = shortdatepattern.Replace("yy", "y");

			btDay.Width = 40;
			btMonth.Width = 80;
			btYear.Width = 40;

			switch (shortdatepattern)
			{
				case "dMy":
					btDay.SetValue(Grid.ColumnProperty, 1);
					btMonth.SetValue(Grid.ColumnProperty, 2);
					btYear.SetValue(Grid.ColumnProperty, 3);
					break;
				case "dyM":
					btDay.SetValue(Grid.ColumnProperty, 1);
					btMonth.SetValue(Grid.ColumnProperty, 3);
					btYear.SetValue(Grid.ColumnProperty, 2);
					break;
				case "Myd":
					btDay.SetValue(Grid.ColumnProperty, 3);
					btMonth.SetValue(Grid.ColumnProperty, 1);
					btYear.SetValue(Grid.ColumnProperty, 2);
					break;
				case "Mdy":
					btDay.SetValue(Grid.ColumnProperty, 2);
					btMonth.SetValue(Grid.ColumnProperty, 1);
					btYear.SetValue(Grid.ColumnProperty, 3);
					break;
				case "yMd":
					btDay.SetValue(Grid.ColumnProperty, 3);
					btMonth.SetValue(Grid.ColumnProperty, 2);
					btYear.SetValue(Grid.ColumnProperty, 1);
					break;
				case "ydM":
					btDay.SetValue(Grid.ColumnProperty, 2);
					btMonth.SetValue(Grid.ColumnProperty, 3);
					btYear.SetValue(Grid.ColumnProperty, 1);
					break;
			}
		}
		private void MarkSelectedDay()
		{
			JumpThruReload = true;
			for (int i = 0; i < DP.Items.Count; i++)
			{
				if (((CalendarDate)DP.Items[i]).Date == Date)
				{
					DP.SelectedIndex = i;
					break;
				}
			}
			JumpThruReload = false;
		}
		private void RotateMonth(DateTime data)
		{
			FrameworkElementFactory f = new FrameworkElementFactory(typeof(UniformGrid));
			f.SetValue(UniformGrid.RowsProperty, 6);
			f.SetValue(UniformGrid.ColumnsProperty, 7);
			DP.ItemsPanel = new ItemsPanelTemplate(f);

			DateTime DateWithDayOne = new DateTime(data.Year, data.Month, 1);
			DP.ItemsSource = GetDays(DateWithDayOne, DateWithDayOne.AddMonths(1).AddMilliseconds(-1), FirstDayOfWeek);
			DP.DisplayMemberPath = "Date.Day";
			DP.SelectedIndex = -1;
		}
		private void SetTextDate(DateTime date)
		{
			string day;
			string month;
			string year;
			day = date.Day.ToString().PadLeft(2, '0');
			month = date.Month.ToString().PadLeft(2, '0');
			year = date.Year.ToString().PadLeft(4, '0');
			txtData.Text = DateMaskFormat;

			if (daystartposition == 0)
				txtData.Text = day + txtData.Text.Substring(2, txtData.Text.Length - 2);
			else if (daystartposition == 3)
				txtData.Text = txtData.Text.Substring(0, 3) + day + txtData.Text.Substring(5, txtData.Text.Length - 5);
			else if (daystartposition == 5)
				txtData.Text = txtData.Text.Substring(0, 5) + day + txtData.Text.Substring(7, txtData.Text.Length - 7);
			else if (daystartposition == 8)
				txtData.Text = txtData.Text.Substring(0, 8) + day;
			if (monthstartposition == 0)
				txtData.Text = month + txtData.Text.Substring(2, txtData.Text.Length - 2);
			else if (monthstartposition == 3)
				txtData.Text = txtData.Text.Substring(0, 3) + month + txtData.Text.Substring(5, txtData.Text.Length - 5);
			else if (monthstartposition == 5)
				txtData.Text = txtData.Text.Substring(0, 5) + month + txtData.Text.Substring(7, txtData.Text.Length - 7);
			else if (monthstartposition == 8)
				txtData.Text = txtData.Text.Substring(0, 8) + month;
			if (yearstartposition == 0)
				txtData.Text = year + txtData.Text.Substring(4, txtData.Text.Length - 4);
			else if (yearstartposition == 3)
				txtData.Text = txtData.Text.Substring(0, 3) + year + txtData.Text.Substring(7, txtData.Text.Length - 7);
			else if (yearstartposition == 6)
				txtData.Text = txtData.Text.Substring(0, 6) + year;
		}
		private void SetTextDate(string date, enmTypeSelection selection)
		{
			string day;
			string month;

			if (String.IsNullOrEmpty(txtData.Text))
				txtData.Text = DateMaskFormat;
			switch (selection)
			{
				case enmTypeSelection.Day:
					day = date.ToString().PadLeft(2, '0');
					if (daystartposition == 0)
						txtData.Text = day + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (daystartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + day + txtData.Text.Substring(5, txtData.Text.Length - 5);
					else if (daystartposition == 5)
						txtData.Text = txtData.Text.Substring(0, 5) + day + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (daystartposition == 8)
						txtData.Text = txtData.Text.Substring(0, 8) + day;
					break;
				case enmTypeSelection.Month:
					month = date.ToString().PadLeft(2, '0');
					if (monthstartposition == 0)
						txtData.Text = month + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (monthstartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + month + txtData.Text.Substring(5, txtData.Text.Length - 5);
					else if (monthstartposition == 5)
						txtData.Text = txtData.Text.Substring(0, 5) + month + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (monthstartposition == 8)
						txtData.Text = txtData.Text.Substring(0, 8) + month;
					break;
				case enmTypeSelection.Year:
					if (yearstartposition == 0)
						txtData.Text = date.ToString().PadLeft(4, '0') + txtData.Text.Substring(4, txtData.Text.Length - 4);
					else if (yearstartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + date.ToString().PadLeft(4, '0') + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (yearstartposition == 6)
						txtData.Text = txtData.Text.Substring(0, 6) + date.ToString().PadLeft(4, '0');
					break;
			}
		}
		private void deleteBlock()
		{
			if (String.IsNullOrEmpty(txtData.Text))
			{
				txtData.Text = DateMaskFormat;
			}
			string strTextoData = string.Empty;
			switch (selecao)
			{
				case enmTypeSelection.Day:
					if (daystartposition == 0)
						txtData.Text = "__" + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (daystartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + "__" + txtData.Text.Substring(5, txtData.Text.Length - 5);
					else if (daystartposition == 5)
						txtData.Text = txtData.Text.Substring(0, 5) + "__" + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (daystartposition == 8)
						txtData.Text = txtData.Text.Substring(0, 8) + "__";
					break;
				case enmTypeSelection.Month:
					if (monthstartposition == 0)
						txtData.Text = "__" + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (monthstartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + "__" + txtData.Text.Substring(5, txtData.Text.Length - 5);
					else if (monthstartposition == 5)
						txtData.Text = txtData.Text.Substring(0, 5) + "__" + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (monthstartposition == 8)
						txtData.Text = txtData.Text.Substring(0, 8) + "__";
					break;
				case enmTypeSelection.Year:
					if (yearstartposition == 0)
						txtData.Text = "____" + txtData.Text.Substring(4, txtData.Text.Length - 4);
					else if (yearstartposition == 3)
						txtData.Text = txtData.Text.Substring(0, 3) + "____" + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (yearstartposition == 6)
						txtData.Text = txtData.Text.Substring(0, 6) + "____";
					break;
			}
			txtData.CaretIndex = index;
			selectDatePart(index, false);
		}
		private void selectDatePart(int intIndex, bool bolAlteraIndex)
		{
			if (intIndex == daystartposition || intIndex == (daystartposition + 1) || intIndex == (daystartposition + 2))
			{
				if (bolAlteraIndex) this.index = daystartposition;
				txtData.CaretIndex = daystartposition;
				txtData.SelectionStart = daystartposition;
				txtData.SelectionLength = 2;
				selecao = enmTypeSelection.Day;
			}
			else if (intIndex == monthstartposition || intIndex == (monthstartposition + 1) || intIndex == (monthstartposition + 2))
			{
				if (bolAlteraIndex) this.index = monthstartposition;
				txtData.CaretIndex = monthstartposition;
				txtData.SelectionStart = monthstartposition;
				txtData.SelectionLength = 2;
				selecao = enmTypeSelection.Month;
			}
			else if (txtData.SelectionStart != yearstartposition && txtData.SelectionLength != 4)
			{
				if (bolAlteraIndex) this.index = yearstartposition;
				txtData.CaretIndex = yearstartposition;
				txtData.SelectionStart = yearstartposition;
				txtData.SelectionLength = 4;
				selecao = enmTypeSelection.Year;
			}
		}
		private void validateInput(char chrEntrada)
		{
			oldDates.Clear();
			if (String.IsNullOrEmpty(txtData.Text))
				txtData.Text = DateMaskFormat;
			string strTextoAnterior = txtData.Text;
			string strAnterior, strProximo, strNovaString;

			if (index >= 10)
			{
				index = 0;
			}
			strAnterior = strTextoAnterior.Substring(0, index);
			strProximo = strTextoAnterior.Substring(index + 1, 9 - index);
			strNovaString = strAnterior + chrEntrada + strProximo;
			txtData.Text = strNovaString;
			index++;
			if ((order[0] == enmTypeSelection.Day && order[1] == enmTypeSelection.Month) || (order[0] == enmTypeSelection.Month && order[1] == enmTypeSelection.Day))
			{
				if (index == 2)
				{
					index++;
					selecao = order[1];
				}
				else if (index == 5)
				{
					index++;
					selecao = order[2];
				}
			}
			else if (order[0] == enmTypeSelection.Year)
			{
				if (index == 4)
				{
					index++;
					selecao = order[1];
				}
				else if (index == 7)
				{
					index++;
					selecao = order[2];
				}
			}
			else if (order[1] == enmTypeSelection.Year)
			{
				if (index == 2)
				{
					index++;
					selecao = order[1];
				}
				else if (index == 7)
				{
					index++;
					selecao = order[2];
				}
			}
			txtData.CaretIndex = index;
			selectDatePart(index, false);

		}
		private void removeDigit()
		{
			if (String.IsNullOrEmpty(txtData.Text))
			{
				txtData.Text = DateMaskFormat;
			}
			string strTextoAnterior = txtData.Text;
			string dia = strTextoAnterior.Substring(daystartposition, 2);
			string mes = strTextoAnterior.Substring(monthstartposition, 2);
			string ano = strTextoAnterior.Substring(yearstartposition, 4);

			switch (selecao)
			{
				case enmTypeSelection.Day:
					if (order[0] == enmTypeSelection.Day)
					{
						txtData.Text = "__" + txtData.Text.Substring(2, txtData.Text.Length - 2);
						selectDatePart(startorder[2], true);
						selecao = order[2];
					}
					else if (order[1] == enmTypeSelection.Day)
					{
						if (daystartposition == 3)
							txtData.Text = txtData.Text.Substring(0, 3) + "__" + txtData.Text.Substring(5, txtData.Text.Length - 5);
						else if (daystartposition == 5)
							txtData.Text = txtData.Text.Substring(0, 5) + "__" + txtData.Text.Substring(7, txtData.Text.Length - 7);
						selectDatePart(startorder[0], true);
						selecao = order[0];
					}
					else if (order[2] == enmTypeSelection.Day)
					{
						txtData.Text = txtData.Text.Substring(0, 8) + "__";
						selectDatePart(startorder[1], true);
						selecao = order[1];
					}
					break;
				case enmTypeSelection.Month:
					if (order[0] == enmTypeSelection.Month)
					{
						txtData.Text = "__" + txtData.Text.Substring(2, txtData.Text.Length - 2);
						selectDatePart(startorder[2], true);
						selecao = order[2];
					}
					else if (order[1] == enmTypeSelection.Month)
					{
						if (monthstartposition == 3)
							txtData.Text = txtData.Text.Substring(0, 3) + "__" + txtData.Text.Substring(5, txtData.Text.Length - 5);
						else if (monthstartposition == 5)
							txtData.Text = txtData.Text.Substring(0, 5) + "__" + txtData.Text.Substring(7, txtData.Text.Length - 7);
						selectDatePart(startorder[0], true);
						selecao = order[0];
					}
					else if (order[2] == enmTypeSelection.Month)
					{
						txtData.Text = txtData.Text.Substring(0, 8) + "__";
						selectDatePart(startorder[1], true);
						selecao = order[1];
					}
					break;
				case enmTypeSelection.Year:
					if (order[0] == enmTypeSelection.Year)
					{
						txtData.Text = "____" + txtData.Text.Substring(4, txtData.Text.Length - 4);
						selectDatePart(startorder[2], true);
						selecao = order[2];
					}
					else if (order[1] == enmTypeSelection.Year)
					{
						txtData.Text = txtData.Text.Substring(0, 3) + "____" + txtData.Text.Substring(7, txtData.Text.Length - 7);
						selectDatePart(startorder[0], true);
						selecao = order[0];
					}
					else if (order[2] == enmTypeSelection.Year)
					{
						txtData.Text = txtData.Text.Substring(0, 6) + "____";
						selectDatePart(startorder[1], true);
						selecao = order[1];
					}
					break;
			}

		}
		private void IncreaseValue()
		{
			adjustDate(enmTypeAdjust.Increase);
		}
		private void DecreaseValue()
		{
			adjustDate(enmTypeAdjust.Decrease);
		}
		private void adjustDate(enmTypeAdjust enmAjuste)
		{
			if (String.IsNullOrEmpty(txtData.Text))
			{
				txtData.Text = DateMaskFormat;
			}
			DateTime datTemp = DateTime.Now;
			string strNumero;
			int intDia, intMes, intAno;

			try
			{
				strNumero = txtData.Text.Substring(daystartposition, 2);
				intDia = Convert.ToInt32(strNumero);
			}
			catch { intDia = datTemp.Day; }

			try
			{
				strNumero = txtData.Text.Substring(monthstartposition, 2);
				intMes = Convert.ToInt32(strNumero);
			}
			catch { intMes = datTemp.Month; }

			try
			{
				strNumero = txtData.Text.Substring(yearstartposition, 4);
				intAno = Convert.ToInt32(strNumero);
			}
			catch { intAno = datTemp.Year; }


			switch (selecao)
			{
				case enmTypeSelection.Day:
					switch (enmAjuste)
					{
						case enmTypeAdjust.Increase:
							intDia++;
							if (intDia > 31) intDia = 1;
							break;
						case enmTypeAdjust.Decrease:
							intDia--;
							if (intDia < 1) intDia = 31;
							break;
					}
					strNumero = intDia.ToString("00");

					if (order[0] == enmTypeSelection.Day)
						txtData.Text = strNumero + txtData.Text.Substring(2);
					else if (order[1] == enmTypeSelection.Day)
					{
						if (daystartposition == 3)
							txtData.Text = txtData.Text.Substring(0, 3) + strNumero + txtData.Text.Substring(5, txtData.Text.Length - 5);
						else if (daystartposition == 5)
							txtData.Text = txtData.Text.Substring(0, 5) + strNumero + txtData.Text.Substring(7, txtData.Text.Length - 7);
					}
					else if (order[2] == enmTypeSelection.Day)
						txtData.Text = txtData.Text.Substring(0, 8) + strNumero;
					break;

				case enmTypeSelection.Month:
					switch (enmAjuste)
					{
						case enmTypeAdjust.Increase:
							intMes++;
							if (intMes > 12) intMes = 1;
							break;
						case enmTypeAdjust.Decrease:
							intMes--;
							if (intMes < 1) intMes = 12;
							break;
					}
					strNumero = intMes.ToString("00");

					if (order[0] == enmTypeSelection.Month)
						txtData.Text = strNumero + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (order[1] == enmTypeSelection.Month)
					{
						if (monthstartposition == 3)
							txtData.Text = txtData.Text.Substring(0, 3) + strNumero + txtData.Text.Substring(5, txtData.Text.Length - 5);
						else if (monthstartposition == 5)
							txtData.Text = txtData.Text.Substring(0, 5) + strNumero + txtData.Text.Substring(7, txtData.Text.Length - 7);
					}
					else if (order[2] == enmTypeSelection.Month)
					{
						txtData.Text = txtData.Text.Substring(0, 8) + strNumero;
					}
					break;

				case enmTypeSelection.Year:
					switch (enmAjuste)
					{
						case enmTypeAdjust.Increase:
							intAno++;
							break;
						case enmTypeAdjust.Decrease:
							intAno--;
							break;
					}
					strNumero = intAno.ToString("0000");

					if (order[0] == enmTypeSelection.Year)
						txtData.Text = strNumero + txtData.Text.Substring(2, txtData.Text.Length - 2);
					else if (order[1] == enmTypeSelection.Year)
						txtData.Text = txtData.Text.Substring(0, 3) + strNumero + txtData.Text.Substring(7, txtData.Text.Length - 7);
					else if (order[2] == enmTypeSelection.Year)
						txtData.Text = txtData.Text.Substring(0, 6) + strNumero;
					break;
			}

			selectDatePart(index, false);
		}
		private ObservableCollection<int> Years(int year)
		{
			ObservableCollection<int> Years = new ObservableCollection<int>();
			if (year - 12 < DateTime.MinValue.Year)
			{
				firstyear = DateTime.MinValue.Year;
				lastyear = firstyear + 24;
			}
			else if (year + 12 > DateTime.MaxValue.Year)
			{
				lastyear = DateTime.MaxValue.Year;
				firstyear = lastyear - 24;
			}
			else
			{
				firstyear = year - 12;
				lastyear = year + 12;
			}
			for (int i = firstyear; i <= lastyear; i++)
				Years.Add(i);
			return Years;
		}
		private ObservableCollection<CalendarDate> GetDays(DateTime firstDate, DateTime lastDate, DayOfWeek firstDayOfWeek)
		{
			DateTime leadingDate = GetPrevDates(firstDate, firstDayOfWeek);
			DateTime trailingDate = GetTrailingDates(firstDate, lastDate, firstDayOfWeek);
			int totalDay = trailingDate.Subtract(leadingDate).Days + 1;

			ObservableCollection<CalendarDate> days = new ObservableCollection<CalendarDate>();
			for (int i = 0; i < totalDay; ++i)
			{
				CalendarDate cDate = new CalendarDate(leadingDate.AddDays(i));
				cDate.IsOtherMonth = (cDate.Date.Month == leadingDate.Month) || (cDate.Date.Month == trailingDate.Month);
				cDate.IsSelectable = IsWhitinRange(cDate.Date, MinDate, MaxDate);
				days.Add(cDate);
			}
			return days;
		}
		private ObservableCollection<string> Months()
		{
			ObservableCollection<string> MonthNames = new ObservableCollection<string>();
			foreach (string month in CultureInfo.CurrentCulture.DateTimeFormat.MonthNames)
			{
				if (month.Length > 0)
					MonthNames.Add(month.Substring(0, 1).ToUpper() + month.Substring(1, 2));
			}
			return MonthNames;
		}
		private ObservableCollection<string> DaysOfWeek()
		{
			ObservableCollection<string> WeekNames = new ObservableCollection<string>();
			foreach (string month in CultureInfo.CurrentCulture.DateTimeFormat.ShortestDayNames)
				WeekNames.Add(month.ToUpper());
			return WeekNames;
		}
		private string MonthName(int month)
		{
			return CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[month - 1].Substring(0, 1).ToUpper() + CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[month - 1].Substring(1, CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[month - 1].Length - 1);
		}
		private System.Windows.Thickness LoadUniformGridMargin(double top, double bottom, double left, double right)
		{
			System.Windows.Thickness t = new Thickness();
			t.Bottom = bottom;
			t.Left = left;
			t.Right = right;
			t.Top = top;
			return t;
		}
		private static DateTime GetPrevDates(DateTime startDate, DayOfWeek firstDayOfWeek)
		{
			DateTime leadingDate;
			try
			{
				leadingDate = startDate.AddDays(-CalculateOffset(startDate, startDate, firstDayOfWeek));
			}
			catch (ArgumentOutOfRangeException)
			{
				leadingDate = DateTime.MinValue;
			}
			return leadingDate;
		}
		private static DateTime GetTrailingDates(DateTime startDate, DateTime endDate, DayOfWeek firstDayOfWeek)
		{
			DateTime trailingDate;
			try
			{
				DateTime tmpStartDate = new DateTime(endDate.Year, endDate.Month, 1);
				int offset = CalculateOffset(startDate, tmpStartDate, firstDayOfWeek);
				trailingDate = tmpStartDate.AddDays(42 - offset - 1);
			}
			catch (ArgumentOutOfRangeException)
			{
				trailingDate = DateTime.MaxValue;
			}
			return trailingDate;
		}
		private static bool IsWhitinRange(DateTime date, DateTime start, DateTime end)
		{
			return CompareYearMonthDay(date, start) >= 0 && CompareYearMonthDay(date, end) <= 0;
		}
		private static int CalculateOffset(DateTime startDate, DateTime currentDate, DayOfWeek firstDayOfWeek)
		{
			int offset;
			if (currentDate.Year == startDate.Year && currentDate.Month == startDate.Month && currentDate.DayOfWeek == firstDayOfWeek)
				offset = 7;
			else
				offset = (currentDate.DayOfWeek - firstDayOfWeek + 7) % 7;
			return offset;
		}

		#endregion

		#region Funções Internas

		internal void DateConfiguration()
		{
			string shortdatepattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
			shortdatepattern = shortdatepattern.Replace(CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator, "");
			order.Clear();
			startorder.Clear();

			while (shortdatepattern.IndexOf("dd") != -1)
			{
				shortdatepattern = shortdatepattern.Replace("dd", "d");
			}
			while (shortdatepattern.IndexOf("MM") != -1)
			{
				shortdatepattern = shortdatepattern.Replace("MM", "M");
			}
			while (shortdatepattern.IndexOf("yy") != -1)
			{
				shortdatepattern = shortdatepattern.Replace("yy", "y");
			}
			switch (shortdatepattern)
			{
				case "dMy":
					daystartposition = 0;
					monthstartposition = 3;
					yearstartposition = 6;
					DateMaskFormat = "__/__/____";
					order.Add(enmTypeSelection.Day);
					startorder.Add(0);
					order.Add(enmTypeSelection.Month);
					startorder.Add(3);
					order.Add(enmTypeSelection.Year);
					startorder.Add(6);
					break;
				case "dyM":
					daystartposition = 0;
					monthstartposition = 8;
					yearstartposition = 3;
					DateMaskFormat = "__/____/__";
					order.Add(enmTypeSelection.Day);
					startorder.Add(0);
					order.Add(enmTypeSelection.Year);
					startorder.Add(3);
					order.Add(enmTypeSelection.Month);
					startorder.Add(8);
					break;
				case "Myd":
					daystartposition = 8;
					monthstartposition = 0;
					yearstartposition = 3;
					DateMaskFormat = "__/____/__";
					order.Add(enmTypeSelection.Month);
					startorder.Add(0);
					order.Add(enmTypeSelection.Year);
					startorder.Add(3);
					order.Add(enmTypeSelection.Day);
					startorder.Add(8);
					break;
				case "Mdy":
					daystartposition = 3;
					monthstartposition = 0;
					yearstartposition = 6;
					DateMaskFormat = "__/__/____";
					order.Add(enmTypeSelection.Month);
					startorder.Add(0);
					order.Add(enmTypeSelection.Day);
					startorder.Add(3);
					order.Add(enmTypeSelection.Year);
					startorder.Add(6);
					break;
				case "yMd":
					daystartposition = 8;
					monthstartposition = 5;
					yearstartposition = 0;
					DateMaskFormat = "____/__/__";
					order.Add(enmTypeSelection.Year);
					startorder.Add(0);
					order.Add(enmTypeSelection.Month);
					startorder.Add(5);
					order.Add(enmTypeSelection.Day);
					startorder.Add(8);
					break;
				case "ydM":
					daystartposition = 5;
					monthstartposition = 8;
					yearstartposition = 0;
					DateMaskFormat = "____/__/__";
					order.Add(enmTypeSelection.Year);
					startorder.Add(0);
					order.Add(enmTypeSelection.Day);
					startorder.Add(5);
					order.Add(enmTypeSelection.Month);
					startorder.Add(8);
					break;
			}
		}
		internal static int CompareYearMonthDay(DateTime date1, DateTime date2)
		{
			DateTime first = new DateTime(date1.Year, date1.Month, date1.Day);
			DateTime second = new DateTime(date2.Year, date2.Month, date2.Day);
			TimeSpan ts = first - second;
			return ts.Days;
		}

		#endregion

		protected virtual void UpdateValitadions()
		{
			//if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
			//    return;

			if (this.ValidationRules.Contains(DateValidationRuleName))
			{
				DateValidationRule ValidationRule = this.ValidationRules[DateValidationRuleName] as DateValidationRule;
				if (ValidationRule != null)
				{
					ValidationRule.ErrorContent = InvalidDateErrorMessage;
					ValidationRule.IsEnabled = true;
				}
			}
			if (this.ValidationRules.Contains(RequiredValidationRuleName))
			{
				RequiredDateValidationRule reqValidation = this.ValidationRules[RequiredValidationRuleName] as RequiredDateValidationRule;
				if (reqValidation != null)
				{
					reqValidation.ErrorContent = RequiredErrorMessage;
					reqValidation.IsEnabled = this.IsRequired;
				}
			}
			if (this.ValidationRules.Contains(RangeValidationRuleName))
			{
				RangeValidationRule RangeValidation = this.ValidationRules[RangeValidationRuleName] as RangeValidationRule;
				if (RangeValidation != null)
				{
					RangeValidation.ErrorContent = RangeOverflowErrorMessage;
					RangeValidation.Maximum = MaxDate;
					RangeValidation.Minimum = MinDate;
					RangeValidation.IsEnabled = true;
				}
			}

		}

		#region IValidatable Members

		public static readonly DependencyProperty CanValidateProperty = ValidationManager.CanValidateProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Indica se o objeto suporta validação
		/// </summary>
		public bool CanValidate
		{
			get { return (bool)GetValue(CanValidateProperty); }
		}

		public static readonly DependencyProperty ValidationGroupProperty = ValidationManager.ValidationGroupProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Grupo de validação do objeto, informar null ou string.Empty nos objetos que disparam 
		/// validação para ignorar o grupo de validação
		/// </summary>
		public string ValidationGroup
		{
			get { return (string)GetValue(ValidationGroupProperty); }
			set { SetValue(ValidationGroupProperty, value); }
		}
		#endregion

		#region IValidatableObject Members

		public static readonly DependencyProperty ClearServiceErrorsProperty = ValidationManager.ClearServiceErrorsProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Indica se o objeto dispara validação
		/// </summary>
		public bool ClearServiceErrors
		{
			get { return (bool)GetValue(ClearServiceErrorsProperty); }
			set { SetValue(ClearServiceErrorsProperty, value); }
		}

		public static readonly DependencyProperty CausesValidationProperty = ValidationManager.CausesValidationProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Indica se o objeto dispara validação
		/// </summary>
		public bool CausesValidation
		{
			get { return (bool)GetValue(CausesValidationProperty); }
			set { SetValue(CausesValidationProperty, value); }
		}

		public static readonly DependencyProperty ValidationTriggersProperty = ValidationManager.ValidationTriggersProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Triggers que disparam a validação do objeto
		/// </summary>
		public ValidationTriggerCollection ValidationTriggers
		{
			get { return (ValidationTriggerCollection)GetValue(ValidationTriggersProperty); }
		}

		public static readonly DependencyProperty ValidationRulesProperty = ValidationManager.ValidationRulesProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Regras de validação do objeto
		/// </summary>
		public ValidationRuleCollection ValidationRules
		{
			get { return (ValidationRuleCollection)GetValue(ValidationRulesProperty); }
		}

		public static readonly DependencyProperty HasErrorProperty = ValidationManager.HasErrorProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Indica se objeto tem erros
		/// </summary>
		public bool HasError
		{
			get { return (bool)GetValue(HasErrorProperty); }
		}

		public static readonly DependencyProperty ErrorsProperty = ValidationManager.ErrorsProperty.AddOwner(typeof(DatePicker));

		/// <summary>
		/// Erros do objeto
		/// </summary>
		public ReadOnlyObservableCollection<ValidationError> Errors
		{
			get { return (ReadOnlyObservableCollection<ValidationError>)GetValue(ErrorsProperty); }
		}

		public static readonly DependencyProperty ErrorTemplateProperty = ValidationManager.ErrorTemplateProperty.AddOwner(typeof(DatePicker));

		/// <summary>
		/// Template aplicado quando objeto tem erros
		/// </summary>
		public ControlTemplate ErrorTemplate
		{
			get { return (ControlTemplate)GetValue(ErrorTemplateProperty); }
			set { SetValue(ErrorTemplateProperty, value); }
		}

		/// <summary>
		/// Valida todas as properties do objeto
		/// </summary>
		/// <returns>True se todas as properties forem válidas</returns>
		public bool Validate()
		{
			return ValidationManager.Validate(this);
		}

		/// <summary>
		/// Valida a property informada do objeto
		/// </summary>
		/// <param name="property">Property a ser validada</param>
		/// <returns>True se a property for válida</returns>
		public bool Validate(DependencyProperty property)
		{
			return ValidationManager.Validate(this, property);
		}

		/// <summary>
		/// Valida todos os objetos do container pai do objeto
		/// </summary>
		/// <returns>True se todos os objetos forem válidos</returns>
		public bool ValidateParentContainer()
		{
			return ValidationManager.ValidateParentContainer(this);
		}

		#endregion

        #region INotifyPropertyChanged Members

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            //if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            //    return;

            base.OnPropertyChanged(e);

            if (e.Property == ValueProperty)
            {
                RoutedEventArgs eValueChanged = new RoutedEventArgs(ValueChangedEvent, this);
                this.RaiseEvent(eValueChanged);
            }

            OnPropertyChanged(e.Property.Name);
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

        #endregion

		#region ChangesMonitor
		private int? _sourceObjectHashCode;

		public static readonly DependencyProperty IsChangeMonitoredProperty = ChangesMonitorManager.IsChangeMonitoredProperty.AddOwner(typeof(DatePicker));
		/// <summary>
		/// Indica se as alteracoes do objeto serao monitoradas pelo ChangesMonitorContainer
		/// </summary>
		public bool IsChangeMonitored
		{
			get { return (bool)GetValue(IsChangeMonitoredProperty); }
			set { SetValue(IsChangeMonitoredProperty, value); }
		}

		void _Loaded(object sender, RoutedEventArgs e)
		{
			this.Drop += new DragEventHandler(DatePicker_Drop);
			this.DragEnter += new DragEventHandler(DatePicker_DragEnter);
			ChangesMonitorContainer container = ChangesMonitorManager.GetParentChangesMonitorContainer(this);
			if (container != null)
				container.CleaningChanges += new RoutedEventHandler(container_CleaningChanges);

			//Aplica estilo para sina
			TemplateHelper.ApplyGridTemplate(this);
		}

		void DatePicker_DragEnter(object sender, DragEventArgs e)
		{
			e.Handled = true;
		}

		void DatePicker_Drop(object sender, DragEventArgs e)
		{
			e.Handled = true;
		}

		void container_CleaningChanges(object sender, RoutedEventArgs e)
		{
			this._sourceObjectHashCode = null;
		}

		/// <summary>
		/// Recuperar o binding para as propriedades de entrada do controle
		/// No caso do combo box , as propriedades permitdas são 3
		/// SelectedValueProperty
		/// SelectedItemProperty
		/// SelectedIndexProperty
		/// </summary>
		/// <returns></returns>
		protected Binding GetBindingOfInputProperty()
		{
			return BindingOperations.GetBinding(this, DatePicker.ValueProperty);
		}

		/// <summary>
		/// Verificar se a propriedade alterada é a propriedade default do controle
		/// e disparar o evento de alteracao quando for preciso
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void _PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (this.IsChangeMonitored && e.PropertyName == ChangesMonitorManager.GetDefaultPropertyAttribute(this))
			{
				bool hasChanges = true;

				Binding bind = GetBindingOfInputProperty();
				//se tiver biding associado 
				if (bind != null)
				{
					//recuperar o hashCode do objeto source do binding
					int? objectHashCode = this.GetHashCodeOfSourceObject(bind);

					//se nao houve um objeto source dos dados (ou seja, se nao houver binding)
					//disparar sempre o evento de indicacao de alteracao
					if (objectHashCode.HasValue)
					{
						//se for um objeto diferente do atual, significa que houve uma alteração no bindig, sendo assim
						//nao dever ser disparado o evento de indicacao de alteracao para o changes monitor
						if (_sourceObjectHashCode != objectHashCode)
						{
							_sourceObjectHashCode = objectHashCode;
							hasChanges = false;
						}
					}
					////se havia um objeto source e nao existe mais, limpar o hashcode e nao disparar o evento de indicacao de alteracao
					else
					{
						_sourceObjectHashCode = objectHashCode;
						hasChanges = false;
					}
				}

				if (hasChanges)
				{
					RoutedEventArgs controlHasChangesEventArgs = new RoutedEventArgs(ChangesMonitorManager.ControlHasChangedEvent, this);
					this.RaiseEvent(controlHasChangesEventArgs);
				}
			}
		}
		#endregion
	}

	public class DateConverter : IValueConverter
	{
		DatePicker _datePicker;

		public DateConverter(DatePicker datePicker)
		{
			this._datePicker = datePicker;
		}

		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value != null)
			{
				DateTime result = DateTime.Parse(value.ToString());
				return result.ToString(DateCultureInfoHelper.CustomDateFormat(false)).Replace(".", "/");
			}
			return null;
		}

		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (value == null || (value != null && String.IsNullOrEmpty(value.ToString())))
				return null;

			DateTime Result;
			string dateToValidate = "";

			if (_datePicker.Value != null)
				dateToValidate = value.ToString().Replace("/", ".") + " " + _datePicker.Value.Value.ToString("HH:mm:ss");
			else
				dateToValidate = value.ToString().Replace("/", ".") + " 00:00:00";

			if (DateTime.TryParseExact(dateToValidate, DateCultureInfoHelper.CustomDateFormat(true), null, DateTimeStyles.None, out Result))
				return Result;
			else
				return null;
		}

		//string GetDateTimeMask()
		//{
		//    string shortdatepattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
		//    shortdatepattern = shortdatepattern.Replace(CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator, "");

		//    while (shortdatepattern.IndexOf("dd") != -1)
		//        shortdatepattern = shortdatepattern.Replace("dd", "d");
		//    while (shortdatepattern.IndexOf("MM") != -1)
		//        shortdatepattern = shortdatepattern.Replace("MM", "M");
		//    while (shortdatepattern.IndexOf("yy") != -1)
		//        shortdatepattern = shortdatepattern.Replace("yy", "y");

		//    switch (shortdatepattern)
		//    {
		//        case "dMy":
		//            return "__/__/____";
		//        case "dyM":
		//            return "__/____/__";
		//        case "Myd":
		//            return "__/____/__";
		//        case "Mdy":
		//            return "__/__/____";
		//        case "yMd":
		//            return "____/__/__";
		//        case "ydM":
		//            return "____/__/__";
		//        default:
		//            return "__/__/____";
		//    }
		//}
	}
}